#pragma once

#include <boost/variant.hpp>

namespace alpha { namespace utility {

template <typename Derived, template <typename> class Tmpl>
struct datatype: public Tmpl<Derived>
{
	// constructors
	datatype() {}
	
	template <typename T>
	datatype(T const &v) : variant_(v) {}
	
	datatype(Derived const &v) : variant_(v.variant_) {}
	
	// assign
	template <typename T>
	void assign(T const &v)
	{
		this->variant_ = v;
	}

	void assign(Derived const &v)
	{
		this->variant_ = v.variant_;
	}

	// conversions
	template <typename T>
	T const * pointer() const
	{
		return boost::get<T>(&variant_);
	}

	template <typename T>
	T * pointer()
	{
		return boost::get<T>(&variant_);
	}

	template <typename T>
	T const & reference() const
	{
		return boost::get<T>(variant_);
	}

	template <typename T>
	T & reference()
	{
		return boost::get<T>(variant_);
	}

	// swap
	void swap(Derived const &v)
	{
		this->variant_.swap(v.variant_);
	}

private:

	typename boost::make_variant_over<
		typename Tmpl<Derived>::type
		>::type variant_;
};

}} // namespace alpha::utility
